import json
import os
import pyautogui
from pynput import keyboard
import tkinter as tk
from tkinter import messagebox

from scrollable_widgets import create_scrollable_text
from utils import create_centered_window, bind_mousewheel


class Recorder:
    def __init__(self, main_window=None, workflow_dir="workflows"):
        # 确保工作流目录存在
        self.workflow_dir = workflow_dir
        if not os.path.exists(workflow_dir):
            os.makedirs(workflow_dir)

        self.listener = None  # 键盘监听器对象
        self.steps = []  # 存储录制的操作步骤列表
        self.filename = ""  # 保存录制结果的文件路径
        self.free_input_mode = False  # 自由输入模式开关
        self.typed_text = ""  # 在自由输入模式下存储用户输入的文本
        self.main_window = main_window  # 主窗口引用

        # UI组件
        self.filename_entry = None
        self.start_button = None
        self.stop_button = None
        self.log_area = None

        self.root = create_centered_window(title="录制模式 - 自动化执行系统", width=600, height=500, window_type='top',
                                           parent=main_window)
        # 录制窗口关闭返回主窗口
        self.root.protocol("WM_DELETE_WINDOW", self.back_to_main)
        self.create_ui()
        # 在初始化时显示使用说明
        self.show_instructions()

    def log_message(self, message):
        """在日志区域显示消息"""
        # 检查日志区域是否存在
        if self.log_area:
            # 临时启用日志区域以便添加新内容
            self.log_area.config(state=tk.NORMAL)
            # 在日志区域末尾插入新消息并换行
            self.log_area.insert(tk.END, message + "\n")
            # 添加最新消息会自动滚动到日志末尾
            self.log_area.see(tk.END)
            # 重新禁用日志区域保持只读状态
            self.log_area.config(state=tk.DISABLED)

    def show_instructions(self):
        """显示使用说明"""
        self.log_message("=== 全局操作录制工具 ===")
        self.log_message("使用说明:")
        self.log_message("1. 输入流程名称并点击'开始录制'按钮开始录制")
        self.log_message("2. 将鼠标移动到目标位置")
        self.log_message("3. 按对应数字键录制操作:")
        self.log_message("   1 - 单击当前位置")
        self.log_message("   2 - 双击当前位置")
        self.log_message("   直接按回车键 - 按回车键")
        self.log_message("   Ctrl - 开启/关闭自由输入模式")
        self.log_message("4. 自由输入模式下:")
        self.log_message("   - 直接输入任意文本")
        self.log_message("   - 按Ctrl键结束输入并保存")
        self.log_message("   - 按ESC键退出录制(自动保存当前输入)")
        self.log_message("5. 按ESC键退出并保存录制结果")

    def on_press(self, key):
        """处理按键事件"""
        try:
            # ESC键: 退出录制 (在任何模式下都应能退出)
            if key == keyboard.Key.esc:
                self.stop_recording()
                return False

            # 如果在自由输入模式下，只处理特殊按键
            if self.free_input_mode:
                # 检查Ctrl键是否被按下，结束自由输入模式并保存文本
                if key in [keyboard.Key.ctrl_l, keyboard.Key.ctrl_r]:
                    self.free_input_mode = False
                    self.save_typed_text()
                    self.log_message(f"\r已关闭自由输入模式")
                    self.log_message("继续录制... (按ESC退出并保存)")

                # 处理可打印字符
                elif hasattr(key, 'char') and key.char is not None:
                    self.typed_text += key.char
                    self.log_message(f"\r正在输入: {self.typed_text}")
                elif key == keyboard.Key.space:
                    self.typed_text += ' '
                    self.log_message(f"\r正在输入: {self.typed_text}")
                elif key == keyboard.Key.backspace and len(self.typed_text) > 0:
                    self.typed_text = self.typed_text[:-1]
                    self.log_message(f"\r正在输入: {self.typed_text}")

            else:
                # 正常录制模式
                # Ctrl键: 开启自由输入模式
                if key in [keyboard.Key.ctrl_l, keyboard.Key.ctrl_r]:
                    self.free_input_mode = True
                    self.typed_text = ""
                    self.log_message(f"\r已开启自由输入模式，请直接输入文本...")
                    self.log_message("输入完成后按Ctrl键结束输入并保存")

                # 数字键1: 单击操作
                elif hasattr(key, 'char') and key.char == '1':
                    x, y = pyautogui.position()
                    step = {
                        "name": f"点击位置 ({x}, {y})",
                        "x": x,
                        "y": y,
                        "type": "click"
                    }
                    self.steps.append(step)
                    self.log_message(f"\r已记录单击操作: ({x}, {y})")
                    pyautogui.click(x, y)
                    self.log_message(f"\r已执行单击操作: ({x}, {y})")
                    self.log_message("继续录制... (按ESC退出并保存)")

                # 数字键2: 双击操作
                elif hasattr(key, 'char') and key.char == '2':
                    x, y = pyautogui.position()
                    step = {
                        "name": f"双击位置 ({x}, {y})",
                        "x": x,
                        "y": y,
                        "type": "double_click"
                    }
                    self.steps.append(step)
                    self.log_message(f"\r已记录双击操作: ({x}, {y})")
                    pyautogui.doubleClick(x, y)
                    self.log_message(f"\r已执行双击操作: ({x}, {y})")
                    self.log_message("继续录制... (按ESC退出并保存)")

                # 直接按回车键: 键盘输入回车 (只在非自由输入模式下处理)
                elif key == keyboard.Key.enter:
                    step = {
                        "name": "按回车键",
                        "type": "enter"
                    }
                    self.steps.append(step)
                    self.log_message(f"\r已记录回车操作: 按回车")
                    self.log_message("继续录制... (按ESC退出并保存)")

        except Exception as e:
            self.log_message(f"\n按键处理出错: {e}")

    def start_recording(self):
        """启动录制"""
        # 统一重置所有状态
        self.steps = []  # 重置步骤列表
        self.free_input_mode = False  # 重置自由输入模式
        self.typed_text = ""  # 重置输入文本
        if self.listener:  # 停止之前的监听器（如果有的话）
            self.listener.stop()
            self.listener = None

        filename = self.filename_entry.get().strip()
        if not filename:
            filename = "steps"
        self.filename = f"{filename}.json"

        # 构建完整路径
        full_path = os.path.join(self.workflow_dir, self.filename)

        # 删除已存在的文件，确保每次录制都是全新的
        if os.path.exists(full_path):
            result = messagebox.askyesno("文件已存在", f"文件 {self.filename} 已存在，是否覆盖？")

            if not result:
                return

        self.log_message("开始录制...")
        self.log_message("请将鼠标移动到目标位置并按相应按键开始录制")

        # 更新UI状态
        self.start_button.config(state=tk.DISABLED)
        self.stop_button.config(state=tk.NORMAL)
        self.filename_entry.config(state=tk.DISABLED)

        self.listener = keyboard.Listener(on_press=self.on_press)
        self.listener.start()

    def save_typed_text(self):
        """保存已输入的文本"""
        if self.typed_text:
            step = {
                "name": f"输入文本: {self.typed_text}",
                "type": "input",
                "value": self.typed_text
            }
            self.steps.append(step)
            self.log_message(f"\r已记录输入操作: 输入'{self.typed_text}'")
            self.typed_text = ""

    def stop_recording(self):
        """停止录制并保存结果"""
        # 检查是否有未保存的文本
        self.save_typed_text()
        self.log_message(f"\n录制已停止，共记录 {len(self.steps)} 个操作")

        # 如果步骤列表不为空，则保存结果
        if self.steps:
            # 创建完整的JSON结构，包含步骤steps、默认延时设置delay_settings和自定义延时设置custom_delay_settings
            workflow_data = {
                "steps": self.steps,
                "delay_settings": {
                    "click": 1.0,
                    "double_click": 1.0,
                    "input": 1.0,
                    "enter": 1.0,
                    "default": 1.0
                },
                "custom_delay_settings": {}
            }

            full_path = os.path.join(self.workflow_dir, self.filename)
            with open(full_path, 'w', encoding='utf-8') as f:
                # 保存JSON数据，ensure_ascii=False 保留原始字符编码（如中文），避免转义为\uXXXX格式，indent=2 设置2个空格的缩进格式
                json.dump(workflow_data, f, ensure_ascii=False, indent=2)
            self.log_message(f"录制结果已保存为 {full_path} 格式，可直接用于执行器")

        # 更新UI状态，开始按钮启用，停止按钮禁用，文件名输入框启用
        self.start_button.config(state=tk.NORMAL)
        self.stop_button.config(state=tk.DISABLED)
        self.filename_entry.config(state=tk.NORMAL)

        # 停止监听器
        if self.listener:
            self.listener.stop()
            self.listener = None

    def back_to_main(self):
        """返回主菜单"""
        # 如果仍在录制中，则停止并保存录制内容
        if self.listener and self.listener.is_alive():
            self.stop_recording()

        # 销毁录制窗口
        self.root.destroy()
        # 显示主窗口
        self.main_window.deiconify()

    def create_ui(self):
        """创建UI界面"""
        # 主框架
        main_frame = tk.Frame(self.root, padx=10, pady=10)
        main_frame.pack(expand=True, fill=tk.BOTH)

        # 标题
        title_label = tk.Label(main_frame, text="录制模式", font=("微软雅黑", 16, "bold"))
        title_label.pack(pady=(0, 10))

        # 文件名输入
        file_frame = tk.Frame(main_frame)
        file_frame.pack(pady=(0, 10))

        tk.Label(file_frame, text="流程名称:").pack(side=tk.LEFT)
        self.filename_entry = tk.Entry(file_frame)
        self.filename_entry.pack(side=tk.LEFT, padx=5)
        tk.Label(file_frame, text=".json").pack(side=tk.LEFT)

        # 控制按钮
        button_frame = tk.Frame(main_frame)
        button_frame.pack(pady=(0, 10))

        # 在任何时刻，要么可以开始录制（开始按钮可用，停止按钮禁用），要么正在录制（开始按钮禁用，停止按钮可用）
        self.start_button = tk.Button(button_frame, text="开始录制", command=self.start_recording)
        self.start_button.pack(side=tk.LEFT, padx=(0, 5))

        # 禁用停止按钮
        self.stop_button = tk.Button(button_frame, text="停止录制", command=self.stop_recording, state=tk.DISABLED)
        self.stop_button.pack(side=tk.LEFT, padx=(0, 5))

        back_button = tk.Button(button_frame, text="返回主菜单", command=self.back_to_main)
        back_button.pack(side=tk.LEFT)

        # 日志区域
        log_frame = tk.LabelFrame(main_frame, text="录制日志", padx=10, pady=10)
        log_frame.pack(fill=tk.BOTH, expand=True)

        # 创建带滚动条的日志区域，state=tk.DISABLED 将 Text 组件变为只读状态，用户无法编辑其中的内容
        self.log_area = create_scrollable_text(log_frame, state=tk.DISABLED)
        self.log_area.pack(fill=tk.BOTH, expand=True)

        # 给Text组件绑定滚动，并且覆盖掉默认行为
        bind_mousewheel(self.log_area)
        # 给根窗口绑定滚动
        bind_mousewheel(self.log_area, self.root)
